/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package continuity;

import continuity.View.MapView;
import continuity.View.RoomView;
import java.io.BufferedReader;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
 *
 * @author FornetTeam
 */
public class Map {
    /**
     * A területen lévő helyiségek listája.
     */
    private List<Room> rooms;
    
    /**
     * Map konstruktora.
     * @param game A Communication interfész.
     * @param characters A játék karakterei.
     * @param filename A fájl neve, amiben a Map leírása van.
     */
    public Map(Communication game, ArrayList<Character> characters, String filename) throws IOException {
        rooms=new ArrayList<Room>();
        int width, height, numberOfKeys, numberOfCompatible;
        try {
            BufferedReader br=new BufferedReader(new FileReader(filename));
            String[] s=br.readLine().split(" ");
            //4 szám beolvasása
            height=Integer.parseInt(s[0]);
            width=Integer.parseInt(s[1]);
            numberOfKeys=Integer.parseInt(s[2]);
            numberOfCompatible=Integer.parseInt(s[3]);
            ArrayList<String> compatibles=new ArrayList<String>();
            DoorElement door=new DoorElement(game, numberOfKeys);
            //kompatibilitások beolvasása
            for(int i=0;i<numberOfCompatible;i++) {
                compatibles.add(br.readLine());
            }
            for(int i=0;i<height;i++) {
                for(int j=0;j<width;j++) {
                    ArrayList<String> description=new ArrayList<String>();
                    String line=br.readLine();
                    while(line != null &&
                            line.equals("") == false) {
                        description.add(line);
                        line=br.readLine();
                    }
                    //szoba létrehozása
                    rooms.add(new Room(game, characters, description, door));
                }
                //a külön sorban lévő szobák leírása között két üres sor van
                br.readLine();
            }
            
            //kompatibilitások feldolgozása
            for(int i=0;i<compatibles.size();i++) {
                String[] str=compatibles.get(i).split(" ");
                int a=Integer.parseInt(str[0]);
                int b=Integer.parseInt(str[1]);
                int c=Integer.parseInt(str[2]);
                rooms.get(a).addCompatible(rooms.get(b), Direction.intToDirection(c));
            }
            //szomszédságok beállítása
            for(int i=0;i<rooms.size();i++) {
                Room r=rooms.get(i);
                //nem alsó sor indexei
                if(i<width*(height-1)) {
                    r.setNeighbor(rooms.get(i+width), Direction.Down);
                }
                 //nem felső sor indexei
                if(i>=width) {
                    r.setNeighbor(rooms.get(i-width), Direction.Up);
                }
                //nem bal oldal indexei
                if(i%width!=0) {
                    r.setNeighbor(rooms.get(i-1), Direction.Left);
                }
                //nem jobb oldal indexei
                if(i%width!=width-1) {
                    r.setNeighbor(rooms.get(i+1), Direction.Right);
                }
            }
        } catch (IOException ex) {
            Logger.getLogger(Map.class.getName()).log(Level.SEVERE, null, ex);
            throw ex;
        }
    }
    
    /**
     * A megfelelő irányban cseréli az üres 
     * helyiséget valamelyik szomszédjával. 
     * Emellett beállítja a cserében résztvevő 
     * helyiségek kapcsolódó mezőinek kapcsolatait
     * @param direction A mozgatás iránya
     */
    public boolean swap(Direction direction) {
        //emptyRoom megkeresése
        Room empty=null;
        for(int i=0;i<rooms.size();i++) {
            Room r=rooms.get(i);
            if(r.getBorderNode(Direction.Up, 0)==null &&
                    r.getBorderNode(Direction.Down, 0)==null &&
                    r.getBorderNode(Direction.Right, 0)==null &&
                    r.getBorderNode(Direction.Left, 0)==null) {
                empty=r;
                break;
            }
        }
        if(empty==null) {
            //nincs EmptyRoom a pályán, nem mozgathatunk szobákat.
            return false;
        }
        //ha van a megfelelő oldalon szomszédja, csak akkor lesz csere + a végén return true, mert volt csere
        if(empty.getNeighbor(direction) != null) {
            Direction[] dirs = {Direction.Up, Direction.Down, Direction.Left, Direction.Right};
            Room r=empty.getNeighbor(direction);
            for(int i=0;i<dirs.length;i++) {
                Direction actual=dirs[i];
                /**
                 * Ha az aktuális I irány megegyezik a direction változóval
                 */
                if(actual==direction) {
                    if(r.getNeighbor(actual)!=null) {
                        r.getNeighbor(actual).setNeighbor(empty, actual.getOpposite());
                    }
                    empty.setNeighbor(r.getNeighbor(actual), actual);
                    r.setNeighbor(empty, actual);
                }
                /**
                 * Ha az aktuális I irány megegyezik a direction ellentétével
                 */
                else if(actual==direction.getOpposite()) {
                    if(empty.getNeighbor(actual) != null) {
                        empty.getNeighbor(actual).setNeighbor(r, actual.getOpposite());
                    }
                    r.setNeighbor(empty.getNeighbor(actual), actual);
                    empty.setNeighbor(r, actual);
                }
                /**
                 * Ha egyik előző sem teljesül
                 */
                else {
                    Room n1=empty.getNeighbor(actual);
                    Room n2=r.getNeighbor(actual);
                    if(n1!=null) {
                        n1.setNeighbor(r, actual.getOpposite());
                    }
                    if(n2!=null) {
                        n2.setNeighbor(empty, actual.getOpposite());
                    }
                    empty.setNeighbor(n2, actual);
                    r.setNeighbor(n1, actual);
                }
            }
            //volt csere
            return true;
        }
        //nem volt csere
        return false;
    }
    
    private Room findLeftUpRoom() {
        for(int i=0;i<rooms.size();i++) {
            Room r = rooms.get(i);
            if(r.getNeighbor(Direction.Left)==null &&
                    r.getNeighbor(Direction.Up)==null) {
                return r;
            }
        }
        return null;
    }
    
    @Override
    public String toString() {
        String eol=System.getProperty("line.separator");
        String ret="";
        int height=0;
        int width=0;
        Room r=findLeftUpRoom();
        while(r != null) {
            Room now=r;
            while(now !=null) {
                ret+=now.toString()+ eol;
                now=now.getNeighbor(Direction.Right);
                if(height==0) width++;
            }
            r=r.getNeighbor(Direction.Down);
            if(r != null) {
                ret+=eol;
            }
            height++;
        }
        ret=ret.substring(0, ret.length()-2);
        ret=height + " " + width + eol + ret;
        return ret;
    }
    
    public MapView createMapView() {
        int height=0;
        int width=0;
        
        Room r=findLeftUpRoom();
        //meghatározzuk, hogy hány szoba van egy oszlopban
        Room temp=r;
        while(temp!=null) {
            height++;
            temp=temp.getNeighbor(Direction.Down);
        }
        //meghatározzuk, hogy hány szoba van egy sorban
        temp=r;
        while(temp!=null) {
            width++;
            temp=temp.getNeighbor(Direction.Right);
        }
        //megfelelő méretű tömb létrehozása
        RoomView[][] roomViews=new RoomView[height][width];
        //bejárás balról jobbra, fentről le + empty room helyzet meghatározás
        int emptyRoomPositionX=0;
        int emptyRoomPositionY=0;
        int nowx=0;
        while(r!=null) {
            Room now=r;
            int nowy=0;
            while(now!=null) {
                RoomView tmp=now.createRoomView();
                //ha ez az empty, elmentjük a koordinátáit
                if(now.getBorderNode(Direction.Up, 0)==null &&
                    now.getBorderNode(Direction.Down, 0)==null &&
                    now.getBorderNode(Direction.Right, 0)==null &&
                    now.getBorderNode(Direction.Left, 0)==null) {
                    emptyRoomPositionX=nowx;
                    emptyRoomPositionY=nowy;
                }
                roomViews[nowx][nowy]=tmp;
                nowy++;
                now=now.getNeighbor(Direction.Right);
            }
            nowx++;
            r=r.getNeighbor(Direction.Down);
        }
        return new MapView(roomViews, emptyRoomPositionX, emptyRoomPositionY);
    }
}
